From: Keir Fraser Date: Fri, 13 Mar 2009 10:09:25 +0000 (+0000) Subject: xenpm: Add CPU topology info (thread/core/socket) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~13992^2~71 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=550686e4fdd5234b21def5fcbd474e97f3bb4409;p=xen.git xenpm: Add CPU topology info (thread/core/socket) CPU topology info is necessary for power management analysis. For example, to analysis the effect of Px state coordination, Cx package/core coordination, the thread/core/socket topology information is needed. This patch add new command "get-cpu-topology" in xenpm to print the CPU topology info: Signed-off-by: Yu Ke --- diff --git a/tools/libxc/xc_pm.c b/tools/libxc/xc_pm.c index 3b2f314ca2..951c22c5c9 100644 --- a/tools/libxc/xc_pm.c +++ b/tools/libxc/xc_pm.c @@ -306,3 +306,24 @@ int xc_set_cpufreq_para(int xc_handle, int cpuid, return xc_sysctl(xc_handle, &sysctl); } + +int xc_get_cputopo(int xc_handle, struct xc_get_cputopo *info) +{ + int rc; + DECLARE_SYSCTL; + + sysctl.cmd = XEN_SYSCTL_pm_op; + sysctl.u.pm_op.cmd = XEN_SYSCTL_pm_op_get_cputopo; + sysctl.u.pm_op.cpuid = 0; + set_xen_guest_handle( sysctl.u.pm_op.get_topo.cpu_to_core, + info->cpu_to_core ); + set_xen_guest_handle( sysctl.u.pm_op.get_topo.cpu_to_socket, + info->cpu_to_socket ); + sysctl.u.pm_op.get_topo.max_cpus = info->max_cpus; + + rc = do_sysctl(xc_handle, &sysctl); + info->nr_cpus = sysctl.u.pm_op.get_topo.nr_cpus; + + return rc; +} + diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 75995b1a92..bc2e25095b 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -1242,4 +1242,21 @@ int xc_get_cpufreq_para(int xc_handle, int cpuid, int xc_set_cpufreq_gov(int xc_handle, int cpuid, char *govname); int xc_set_cpufreq_para(int xc_handle, int cpuid, int ctrl_type, int ctrl_value); + +struct xc_get_cputopo { + /* IN: maximum addressable entry in + * the caller-provided cpu_to_core/socket. + */ + uint32_t max_cpus; + uint32_t *cpu_to_core; + uint32_t *cpu_to_socket; + + /* OUT: number of cpus returned + * If OUT is greater than IN then the cpu_to_core/socket is truncated! + */ + uint32_t nr_cpus; +}; + +int xc_get_cputopo(int xc_handle, struct xc_get_cputopo *info); + #endif /* XENCTRL_H */ diff --git a/tools/misc/xenpm.c b/tools/misc/xenpm.c index 2cc864cff1..08e26695f9 100644 --- a/tools/misc/xenpm.c +++ b/tools/misc/xenpm.c @@ -58,6 +58,7 @@ void show_help(void) " it is used in ondemand governor.\n" " set-up-threshold [cpuid] set up threshold on CPU or all\n" " it is used in ondemand governor.\n" + " get-cpu-topology get thread/core/socket topology info\n" " start start collect Cx/Px statistics,\n" " output after CTRL-C or SIGINT.\n" ); @@ -750,6 +751,40 @@ out: fprintf(stderr, "failed to set governor name\n"); } +#define MAX_NR_CPU 512 + +void cpu_topology_func(int argc, char *argv[]) +{ + uint32_t cpu_to_core[MAX_NR_CPU]; + uint32_t cpu_to_socket[MAX_NR_CPU]; + struct xc_get_cputopo info; + int i, ret; + + info.cpu_to_core = cpu_to_core; + info.cpu_to_socket = cpu_to_socket; + info.max_cpus = MAX_NR_CPU; + ret = xc_get_cputopo(xc_fd, &info); + if (!ret) + { + printf("CPU\tcore\tsocket\n"); + for (i=0; iu.pm_op.cmd == GET_CPUFREQ_PARA ) - if ( copy_to_guest(u_sysctl, op, 1) ) - { - ret = -EFAULT; - break; - } + if ( copy_to_guest(u_sysctl, op, 1) ) + { + ret = -EFAULT; + break; + } } break; diff --git a/xen/drivers/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c index 78b5fdf143..f2aaca7c24 100644 --- a/xen/drivers/acpi/pmstat.c +++ b/xen/drivers/acpi/pmstat.c @@ -416,6 +416,52 @@ static int set_cpufreq_para(struct xen_sysctl_pm_op *op) return ret; } +static int get_cputopo (struct xen_sysctl_pm_op *op) +{ + uint32_t i, nr_cpus; + XEN_GUEST_HANDLE_64(uint32) cpu_to_core_arr; + XEN_GUEST_HANDLE_64(uint32) cpu_to_socket_arr; + int arr_size, ret=0; + + cpu_to_core_arr = op->get_topo.cpu_to_core; + cpu_to_socket_arr = op->get_topo.cpu_to_socket; + arr_size= min_t(uint32_t, op->get_topo.max_cpus, NR_CPUS); + + if ( guest_handle_is_null( cpu_to_core_arr ) || + guest_handle_is_null( cpu_to_socket_arr) ) + { + ret = -EINVAL; + goto out; + } + + nr_cpus = 0; + for ( i = 0; i < arr_size; i++ ) + { + uint32_t core, socket; + if ( cpu_online(i) ) + { + core = cpu_to_core(i); + socket = cpu_to_socket(i); + nr_cpus = i; + } + else + { + core = socket = INVALID_TOPOLOGY_ID; + } + + if ( copy_to_guest_offset(cpu_to_core_arr, i, &core, 1) || + copy_to_guest_offset(cpu_to_socket_arr, i, &socket, 1)) + { + ret = -EFAULT; + goto out; + } + } + + op->get_topo.nr_cpus = nr_cpus + 1; +out: + return ret; +} + int do_pm_op(struct xen_sysctl_pm_op *op) { int ret = 0; @@ -433,8 +479,6 @@ int do_pm_op(struct xen_sysctl_pm_op *op) if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) ) return -EINVAL; break; - default: - return -ENODEV; } switch ( op->cmd ) @@ -457,6 +501,12 @@ int do_pm_op(struct xen_sysctl_pm_op *op) break; } + case XEN_SYSCTL_pm_op_get_cputopo: + { + ret = get_cputopo(op); + break; + } + default: printk("not defined sub-hypercall @ do_pm_op\n"); ret = -ENOSYS; diff --git a/xen/include/asm-ia64/linux-xen/asm/processor.h b/xen/include/asm-ia64/linux-xen/asm/processor.h index a436fedc96..e54e612c71 100644 --- a/xen/include/asm-ia64/linux-xen/asm/processor.h +++ b/xen/include/asm-ia64/linux-xen/asm/processor.h @@ -198,6 +198,14 @@ DECLARE_PER_CPU(struct cpuinfo_ia64, cpu_info); #define local_cpu_data (&__ia64_per_cpu_var(cpu_info)) #define cpu_data(cpu) (&per_cpu(cpu_info, cpu)) +#ifdef CONFIG_SMP +#define cpu_to_core(cpu) (cpu_data(cpu)->core_id) +#define cpu_to_socket(cpu) (cpu_data(cpu)->socket_id) +#else +#define cpu_to_core(cpu) 0 +#define cpu_to_socket(cpu) 0 +#endif + extern void identify_cpu (struct cpuinfo_ia64 *); extern void print_cpu_info (struct cpuinfo_ia64 *); diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 996734d285..b55bc0234a 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -204,6 +204,9 @@ extern void detect_ht(struct cpuinfo_x86 *c); static always_inline void detect_ht(struct cpuinfo_x86 *c) {} #endif +#define cpu_to_core(_cpu) (cpu_core_id[_cpu]) +#define cpu_to_socket(_cpu) (phys_proc_id[_cpu]) + /* * Generic CPUID function * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index 856ea69df9..7e1a4968f6 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -339,6 +339,24 @@ struct xen_set_cpufreq_para { uint32_t ctrl_type; uint32_t ctrl_value; +} +; +/* Get physical CPU topology information. */ + + +#define INVALID_TOPOLOGY_ID (~0U) +struct xen_get_cputopo { + /* IN: maximum addressable entry in + * the caller-provided cpu_to_core/socket. + */ + uint32_t max_cpus; + XEN_GUEST_HANDLE_64(uint32) cpu_to_core; + XEN_GUEST_HANDLE_64(uint32) cpu_to_socket; + + /* OUT: number of cpus returned + * If OUT is greater than IN then the cpu_to_core/socket is truncated! + */ + uint32_t nr_cpus; }; struct xen_sysctl_pm_op { @@ -350,12 +368,16 @@ struct xen_sysctl_pm_op { #define SET_CPUFREQ_GOV (CPUFREQ_PARA | 0x02) #define SET_CPUFREQ_PARA (CPUFREQ_PARA | 0x03) + /* get CPU topology */ + #define XEN_SYSCTL_pm_op_get_cputopo 0x20 + uint32_t cmd; uint32_t cpuid; union { struct xen_get_cpufreq_para get_para; struct xen_set_cpufreq_gov set_gov; struct xen_set_cpufreq_para set_para; + struct xen_get_cputopo get_topo; }; };